package cn.darkhorse.alarm.service.impl;

import cn.darkhorse.alarm.dto.AlarmRecordInfoDTO;
import cn.darkhorse.alarm.mapper.AlarmRecordInfoMapper;
import cn.darkhorse.alarm.pojo.AlarmParameterSettings;
import cn.darkhorse.alarm.pojo.AlarmRecordInfo;
import cn.darkhorse.alarm.pojo.AlarmRecordTime;
import cn.darkhorse.alarm.service.AlarmParameterSettingsService;
import cn.darkhorse.alarm.service.AlarmRecordInfoService;
import cn.darkhorse.alarm.service.AlarmRecordTimeService;
import cn.darkhorse.alarm.vo.AlarmRecordInfoVO;
import cn.darkhorse.common.constant.CommonConstant;
import cn.darkhorse.device.iot.constant.IotConstant;
import cn.darkhorse.device.pojo.MesDevice;
import cn.darkhorse.device.service.MesDeviceService;
import cn.darkhorse.meswechat.dto.WxSendMessageMoreDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.PageUtils.startPage;


/**
 * <p>
 * 报警记录表 服务实现类
 * </p>
 *
 * @author maoguanjun
 * @since 2023-04-07
 */
@Service
public class AlarmRecordInfoServiceImpl extends ServiceImpl<AlarmRecordInfoMapper, AlarmRecordInfo> implements AlarmRecordInfoService {
    @Resource
    private AlarmRecordInfoMapper alarmRecordInfoMapper;
    @Resource
    private MesDeviceService mesDeviceService;
    @Resource
    private AlarmParameterSettingsService alarmParameterSettingsService;
    @Resource
    private AlarmRecordTimeService alarmRecordTimeService;
    @Resource
    private AlarmParameterSettingsService parameterSettingsService;
    @Resource
    private SysUserMapper userMapper;
    @Resource
    private AlarmRecordInfoService alarmRecordInfoService;
    @Resource
    private RedisCache redisCache;
    /**
     * 列表
     *
     * @param alarmRecordInfoDTO
     * @return
     */
    @Override
    public List<AlarmRecordInfoVO> listAll(AlarmRecordInfoDTO alarmRecordInfoDTO) {
        if(CommonConstant.YES==alarmRecordInfoDTO.getIsPersonal()){
            SysUser user=SecurityUtils.getLoginUser().getUser();
            alarmRecordInfoDTO.setUserId(user.getUserId());
        }
        if(StringUtils.isBlank(alarmRecordInfoDTO.getOrderByDate())){
            alarmRecordInfoDTO.setOrderByDate("desc");
        }

        SysUser sysUser = userMapper.selectUserById(SecurityUtils.getUserId());
        if (sysUser.getCompanyId()!=null){
            alarmRecordInfoDTO.setCompany(sysUser.getCompanyId());
        }
        startPage();
        List<AlarmRecordInfoVO> list=alarmRecordInfoMapper.listAll(alarmRecordInfoDTO);
        return list;
    }

    /**
     * 获取上次报警记录
     *
     * @return
     */
    @Override
    public List<AlarmRecordInfo> getLastRecord() {
        List<AlarmRecordInfo> list=alarmRecordInfoMapper.getLastIntervalRecord();
        return list;
    }

    /**
     * 单条记录处理
     *
     * @param recordId
     * @param handleDescription
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handleSingle(Long recordId, String handleDescription) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info =getById(recordId);
        if(null==info){
            throw new ServiceException("无对应记录！");
        }
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setHandler(user.getUserId());
        info.setAlarmStatus(CommonConstant.YES);
        boolean b = updateById(info);

        //更新报警次数记录
        /*LambdaQueryWrapper<AlarmRecordTime> timeWrapper=new LambdaQueryWrapper<>();
        timeWrapper.eq(AlarmRecordTime::getAlarmRecordId,recordId);
        AlarmRecordTime time=alarmRecordTimeService.getOne(timeWrapper);
        if(null!=time){
            time.setAlarmStatus(CommonConstant.YES);
            alarmRecordTimeService.updateById(time);
        }*/
        boolean result = hasPendingRecords(info);
        if(!result) {
            upRecordTime(info);
        }
        return b;
    }

    /**
     * 根据设备id批量处理
     *
     * @param deviceId
     * @param handleDescription
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean handleByDeviceId(Long deviceId, String handleDescription) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info=new AlarmRecordInfo();
        info.setHandler(user.getUserId());
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setAlarmStatus(CommonConstant.YES);
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        wrapper.eq(AlarmRecordInfo::getDeviceId,deviceId);
        boolean update = update(info, wrapper);
        //更新报警次数记录
        LambdaQueryWrapper<AlarmRecordTime> timeWrapper=new LambdaQueryWrapper<>();
        timeWrapper.eq(AlarmRecordTime::getDeviceId,deviceId);
        timeWrapper.eq(AlarmRecordTime::getAlarmStatus,CommonConstant.NO);
        AlarmRecordTime time=new AlarmRecordTime();
        time.setAlarmStatus(CommonConstant.YES);
        alarmRecordTimeService.update(time,timeWrapper);
        return update;
    }

    /**
     * 根据参数Id批量处理
     *
     * @param paramterId
     * @param handleDescription
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean handleByParameterId(Long paramterId, String handleDescription) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info=new AlarmRecordInfo();
        info.setHandler(user.getUserId());
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setAlarmStatus(CommonConstant.YES);
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        wrapper.eq(AlarmRecordInfo::getParameterId,paramterId);
        boolean update = update(info, wrapper);
        //更新报警次数记录
        LambdaQueryWrapper<AlarmRecordTime> timeWrapper=new LambdaQueryWrapper<>();
        timeWrapper.eq(AlarmRecordTime::getParameterId,paramterId);
        timeWrapper.eq(AlarmRecordTime::getAlarmStatus,CommonConstant.NO);
        AlarmRecordTime time=new AlarmRecordTime();
        time.setAlarmStatus(CommonConstant.YES);
        alarmRecordTimeService.update(time,timeWrapper);
        return update;
    }

    /**
     * 根据设备id批量处理
     *
     * @param deviceId
     * @param handleDescription
     * @param alarmPic
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean handleByDeviceId(Long deviceId, String handleDescription, String alarmPic) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info=new AlarmRecordInfo();
        info.setHandler(user.getUserId());
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setAlarmStatus(CommonConstant.YES);
        info.setAlarmPic(alarmPic);
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        wrapper.eq(AlarmRecordInfo::getDeviceId,deviceId);
        boolean update = update(info, wrapper);
        //更新报警次数记录
        LambdaQueryWrapper<AlarmRecordTime> timeWrapper=new LambdaQueryWrapper<>();
        timeWrapper.eq(AlarmRecordTime::getDeviceId,deviceId);
        timeWrapper.eq(AlarmRecordTime::getAlarmStatus,CommonConstant.NO);
        AlarmRecordTime time=new AlarmRecordTime();
        time.setAlarmStatus(CommonConstant.YES);
        alarmRecordTimeService.update(time,timeWrapper);
        return update;
    }

    /**
     * 根据参数Id批量处理
     *
     * @param paramterId
     * @param handleDescription
     * @param alarmPic
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean handleByParameterId(Long paramterId, String handleDescription, String alarmPic) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info=new AlarmRecordInfo();
        info.setHandler(user.getUserId());
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setAlarmStatus(CommonConstant.YES);
        info.setAlarmPic(alarmPic);
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        wrapper.eq(AlarmRecordInfo::getParameterId,paramterId);
        boolean update = update(info, wrapper);
        //更新报警次数记录
        LambdaQueryWrapper<AlarmRecordTime> timeWrapper=new LambdaQueryWrapper<>();
        timeWrapper.eq(AlarmRecordTime::getParameterId,paramterId);
        timeWrapper.eq(AlarmRecordTime::getAlarmStatus,CommonConstant.NO);
        AlarmRecordTime time=new AlarmRecordTime();
        time.setAlarmStatus(CommonConstant.YES);
        alarmRecordTimeService.update(time,timeWrapper);
        return update;
    }

    /**
     * 倒序取最新5条
     * @return
     */
    @Override
    public List<AlarmRecordInfoVO> listLastFive() {
        List<AlarmRecordInfoVO> voList=alarmRecordInfoMapper.getLastFive();
        return voList;
    }

    /**
     * 是否存在预警记录
     * @param deviceId
     * @param paramterId
     * @return
     */
    @Override
    public boolean hasAlarm(Long deviceId, Long paramterId) {
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        if(null!=deviceId){
            wrapper.eq(AlarmRecordInfo::getDeviceId,deviceId);
            wrapper.groupBy(AlarmRecordInfo::getDeviceId);
        }
        if(null!=paramterId){
            wrapper.eq(AlarmRecordInfo::getParameterId,paramterId);
            wrapper.groupBy(AlarmRecordInfo::getParameterId);
        }
        Long count =count(wrapper);
        return count>0?true:false;
    }

    /**
     * @param recordId
     * @return
     */
    @Override
    public AlarmRecordInfoVO view(Long recordId) {
        AlarmRecordInfo info=getById(recordId);
        AlarmRecordInfoVO vo=new AlarmRecordInfoVO();
        if(null!=info){
            BeanUtils.copyProperties(info,vo);
            MesDevice device=mesDeviceService.getById(info.getDeviceId());
            vo.setDeviceName(device.getName()+"-"+device.getCode());
            AlarmParameterSettings settings=alarmParameterSettingsService.getById(info.getParameterId());
            if(null!=settings) {
                vo.setParamName(StringUtils.isNotBlank(settings.getCustomParameterName()) ? settings.getCustomParameterName() : settings.getPointName());
            }
        }
        return vo;
    }

    /**
     * 拼接待发送消息
     * @return
     */
    @Override
    public List<WxSendMessageMoreDTO> getSendMsg() {
        List<WxSendMessageMoreDTO> sendMsg = alarmRecordInfoMapper.getSendMsg();
        if(null!=sendMsg&&sendMsg.size()>0){
            Map<Long, AlarmParameterSettings> parameterSettingsMap=parameterSettingsService.getMap(null);
            Map<Long, MesDevice> deviceMap=mesDeviceService.list().stream().collect(Collectors.toMap(MesDevice::getId, Function.identity()));
            sendMsg.forEach(item->{
                if(deviceMap.containsKey(item.getDeviceId())){
                    MesDevice device=deviceMap.get(item.getDeviceId());
                    item.setDeviceName(device.getName()+"-"+device.getCode());
                }
                if(parameterSettingsMap.containsKey(item.getParameterId())){
                    AlarmParameterSettings settings=parameterSettingsMap.get(item.getParameterId());
                    String parameter=StringUtils.isNotBlank(settings.getCustomParameterName())?settings.getCustomParameterName():settings.getPointName();
                    item.setWarningParameters(parameter);
                }
            });
        }
        return sendMsg;
    }

    /**
     * 处理单条记录 带图片
     *
     * @param recordId
     * @param handleDescription
     * @param alarmPic
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handleSingle(Long recordId, String handleDescription, String alarmPic) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info =getById(recordId);
        if(null==info){
            throw new ServiceException("无对应记录！");
        }
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setHandler(user.getUserId());
        info.setAlarmStatus(CommonConstant.YES);
        info.setAlarmPic(alarmPic);
        boolean b = updateById(info);

        //更新报警次数记录
        boolean result = hasPendingRecords(info);
        if(!result) {
            upRecordTime(info);
        }

        //20231026  更新设备运行状态
        updateDeviceRunState(info.getDeviceId());

        return b;
    }



    /**
     * 更新设备运行状态
     */
    private void updateDeviceRunState(Long deviceId){
        if(null == deviceId){
            return;
        }
        LambdaUpdateWrapper<MesDevice> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MesDevice::getId,deviceId)
                .set(MesDevice::getDeviceRunningStatus,0);
        mesDeviceService.update(updateWrapper);
    }




    /**
     * 判断是否有未处理的同类型预警
     * @param info
     * @return
     */
    public LambdaQueryWrapper<AlarmRecordInfo> getWrapper(AlarmRecordInfo info){
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getDeviceId,info.getDeviceId());
        wrapper.eq(AlarmRecordInfo::getParameterId,info.getParameterId());
        wrapper.eq(AlarmRecordInfo::getParameterType,info.getParameterType());
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        Integer alarmType=info.getAlarmType();
        //开关量
        if(CommonConstant.ALARM_TYPE_SWITCH_TRUE==alarmType||CommonConstant.ALARM_TYPE_SWITCH_FALSE==alarmType){
            wrapper.eq(AlarmRecordInfo::getAlarmType,info.getAlarmStatus());
        }
        //开关量变化
        if(CommonConstant.ALARM_TYPE_SWITCH_CHANGE==alarmType){
            wrapper.eq(AlarmRecordInfo::getChangeType,info.getChangeType());
        }
        //限值
        if(CommonConstant.ALARM_TYPE_VALUE_LIMIT==alarmType){
            wrapper.eq(AlarmRecordInfo::getLimitType,info.getLimitType());
        }
        //连续
        if(CommonConstant.ALARM_TYPE_VALUE_CONTINUITY==alarmType){
            wrapper.eq(AlarmRecordInfo::getImmediatelyValue,info.getImmediatelyValue());
        }
        return wrapper;
    }
    /**
     * 判断是否有未处理的同类型预警
     * @param info
     * @return
     */
    public LambdaQueryWrapper<AlarmRecordTime> getTimeWrapper(AlarmRecordInfo info){
        LambdaQueryWrapper<AlarmRecordTime> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordTime::getDeviceId,info.getDeviceId());
        wrapper.eq(AlarmRecordTime::getParameterId,info.getParameterId());
        wrapper.eq(AlarmRecordTime::getParameterType,info.getParameterType());
        wrapper.eq(AlarmRecordTime::getAlarmStatus,CommonConstant.NO);
        Integer alarmType=info.getAlarmType();
        //开关量
        if(CommonConstant.ALARM_TYPE_SWITCH_TRUE==alarmType||CommonConstant.ALARM_TYPE_SWITCH_FALSE==alarmType){
            wrapper.eq(AlarmRecordTime::getAlarmType,info.getAlarmStatus());
        }
        //开关量变化
        if(CommonConstant.ALARM_TYPE_SWITCH_CHANGE==alarmType){
            wrapper.eq(AlarmRecordTime::getChangeType,info.getChangeType());
        }
        //限值
        if(CommonConstant.ALARM_TYPE_VALUE_LIMIT==alarmType){
            wrapper.eq(AlarmRecordTime::getLimitType,info.getLimitType());
        }
        //连续
        if(CommonConstant.ALARM_TYPE_VALUE_CONTINUITY==alarmType){
            wrapper.eq(AlarmRecordTime::getImmediatelyValue,info.getImmediatelyValue());
        }
        return wrapper;
    }
    /**
     * 判断是否有未处理的同类型预警
     * @param info
     * @return
     */
    public boolean hasPendingRecords(AlarmRecordInfo info){
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=getWrapper(info);
        long count=alarmRecordInfoService.count(wrapper);
        return count>0?true:false;
    }
    /**
     * 更新报警次数表
     * @param info
     * @return
     */
    public boolean upRecordTime(AlarmRecordInfo info){
        LambdaQueryWrapper<AlarmRecordTime> wrapper=getTimeWrapper(info);
        AlarmRecordTime time = alarmRecordTimeService.getOne(wrapper);
        boolean result=false;
        if (null != time) {
            time.setAlarmStatus(CommonConstant.YES);
            result=alarmRecordTimeService.updateById(time);
        }
        return result;
    }

    /**
     * 批量清除未处理的告警信息
     */
    @Transactional
    @Override
    public boolean clearAll(String handleDescription) {
        SysUser user= SecurityUtils.getLoginUser().getUser();
        AlarmRecordInfo info=new AlarmRecordInfo();
        info.setHandler(user.getUserId());
        info.setHandleDescription(handleDescription);
        info.setHandleDate(LocalDateTime.now());
        info.setAlarmStatus(CommonConstant.YES);
        LambdaQueryWrapper<AlarmRecordInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRecordInfo::getAlarmStatus,CommonConstant.NO);
        boolean update = update(info, wrapper);
        //更新报警次数记录
        LambdaQueryWrapper<AlarmRecordTime> timeWrapper=new LambdaQueryWrapper<>();
        timeWrapper.eq(AlarmRecordTime::getAlarmStatus,CommonConstant.NO);
        AlarmRecordTime time=new AlarmRecordTime();
        time.setAlarmStatus(CommonConstant.YES);
        alarmRecordTimeService.update(time,timeWrapper);
        return update;
    }

    /**
     * 实时报警状态
     * @param deviceId
     * @return
     */
    @Override
    public boolean checkAlarmStatus(Long deviceId) {
//        查询设备最后一条报警信息  如果没处理且时间在60秒内  判断为报警
        AlarmRecordInfo recordInfo = lambdaQuery().eq(AlarmRecordInfo::getDeviceId, deviceId).orderByDesc(AlarmRecordInfo::getCreateTime).last("limit 1").one();
        if (null != recordInfo) {
            if (CommonConstant.NO.equals(recordInfo.getAlarmStatus())) {
                if (LocalDateTime.now().isBefore(recordInfo.getAlarmDate().plusSeconds(IotConstant.DEVICE_ONLINE_TIMEOUT))) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 实时报警状态
     * @param deviceIds
     * @return
     */
    @Override
    public boolean checkAlarmStatus(List<Long> deviceIds) {
//        查询设备最后一条报警信息  如果没处理且时间在60秒内  判断为报警
//        AlarmRecordInfo recordInfo = lambdaQuery().in(AlarmRecordInfo::getDeviceId, deviceIds).orderByDesc(AlarmRecordInfo::getCreateTime).last("limit 1").one();
        for (Long id : deviceIds) {
            AlarmRecordInfo recordInfo = redisCache.getCacheObject(IotConstant.CACHE_MQTT_LIVE_ALARM_DATA + id);
            if (null != recordInfo) {
                System.out.println(recordInfo.getAlarmDate());
                if (CommonConstant.NO.equals(recordInfo.getAlarmStatus())) {
                    if (LocalDateTime.now().isBefore(recordInfo.getAlarmDate().plusSeconds(IotConstant.DEVICE_ONLINE_TIMEOUT))) {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    @Override
    public Map<Long, List<AlarmRecordInfo>> getAllAlarmRecords() {
//        查询60秒内所有未处理的报警
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 计算 60 秒前的时间
        LocalDateTime sixtySecondsAgo = now.minus(60, ChronoUnit.SECONDS);
        List<AlarmRecordInfo> list = lambdaQuery().eq(AlarmRecordInfo::getAlarmStatus, CommonConstant.NO).ge(AlarmRecordInfo::getAlarmDate, sixtySecondsAgo).list();
        if (!list.isEmpty()) {
            Map<Long, List<AlarmRecordInfo>> collected = list.stream().collect(Collectors.groupingBy(AlarmRecordInfo::getDeviceId));
            return collected;
        }

        return new HashMap<Long, List<AlarmRecordInfo>>();
    }

}
